///<reference path="../typings/tsd.d.ts" />
/*使用说明
该功能自动把form标签内，填充上各个表单元素。表单元素在fields中，要一一指定。
在处理tree的下拉时，需要ztree的支持。
当传入values时，通常表示是要编辑数据。它是一个数组，但只用它第一行值。
*/

/**添加编辑窗体的信息描述 */
interface AutoFormFieldsOptions {
    /**对应数据库的字段 */
    field: string;
    /**字段中文描述 */
    title?: string;
    /**类型， 比如string, select,tree,date,number,file .prikey   */
    type: string;
    step?: number; //number类型时，表示它有几位小数。
    /**跨几列 */
    span?: number;

    placeholder?: string;
    /**当类型是树，下拉时，这里提供额外的内容。
     * 当是数组时，根据数组输出
     * 当字符串时，它是请求的url,返回一个数组
     */
    addData?: any[] | string;
}
/**autoform的参数配置 */
interface AutoFormOption {
    /**新增的请求action，
     * 如果存在该参数，则用form submit来提交，否则是ajax提交*/
    action?: string;
    /**ajax提交的地址 */
    ajaxurl?: string;
    /**新增的窗体分几列。 */
    cols?: number;
    /**窗体内容信息 ，如果是prikey，则不输出为显示表单。若要显示主键，则要再写一个普通的field*/
    fields?: AutoFormFieldsOptions[];
    /**所对应的物理表的名称 */
    tableName?: string;
    /**窗体初始值。当编辑功能时，应该传入初始的值,一般只是SQL语句返回的第一行的值 */
    values?: any[];
    canceled?: () => void;
    saved?: (msg: any) => void;
    /**保存点击后，上传之前进行的操作 */
    beforeSave?: (formDatas) => void;
}
interface TreeNode {
    ID: string;
    PID: string;
    NAME: string;
    ISLEAF: string;
    URL?: string;
}
interface SelectNode {
    ID: string;
    MC: string;
}
module AUTO {
    /**依赖日期 控件、zTree   目前假设ID是主键*/
    export class AutoForm {
        /**form本身，必须是form标签 */
        private $form: JQuery;
        /**form 内的table. */
        private $table: JQuery;
        /**保存和取消按钮 */
        private $btnSave: JQuery;
        private $btnCancle: JQuery;
        /**主键记录*/
        private keysList: string[] = [];
        private renderFuncMapper = {
            "string": this.renderString,
            "number": this.renderNumber,
            "select": this.renderSelect,
            "tree": this.renderTree,
            "date": this.renderDate,
            "month": this.renderMonth,
            "year": this.renderYear,
            "file": this.renderFile,
            "textarea": this.renderTextarea,
            "password": this.renderPassword
        };
        private _opt: AutoFormOption = {
            action: "",
            ajaxurl: "",
            cols: 2,
            fields: [],
            tableName: "",
            values: []
        };
        /** 等待个数。因为有些是异步插入的，要等这些异步完成才行 */
        private waitCount = 0;
        constructor(element: Element, option: AutoFormOption) {
            this._opt = $.extend(this._opt, option);
            this.$form = $(element);
            this.init();
            this.renderTable();
            if (this._opt.values.length) {
                this.writeValues();
            }
            this.bindClickEvent();
            this.$form.data("autoform", this);
        }
        public init() {
            this.$form.empty()
                .prop("action", this._opt.action)
                .addClass("autoForm")
                .append(`<table class='autoFormTable'></table>
                        <br>
        <div class="autoFormDiv">
            <button type="button" class="btn btn-warning btnCancel">
                <span class="glyphicon glyphicon-remove"></span> 取&nbsp;&nbsp;消
            </button>
            <button type="submit" class="btn btn-info btnSave">
                <span class="glyphicon glyphicon-ok"></span> 保&nbsp;&nbsp;存
            </button>
        </div>`);
            this.$table = this.$form.find(".autoFormTable");
            this.$btnSave = this.$form.find(".btnSave");
            this.$btnCancle = this.$form.find(".btnCancel");
        }
        /**根据字段，输出到form的table标签中去,之后绑定日期的功能 .
         * 如果类型是prikey,则添加到form，而不是添加到table中支 */

        public renderTable() {
            let scope = this;
            let content = "<tbody><tr>"; //输出到tbody中的内容
            let pos = 0;             //用来判断当前位置是否能容下一个字段
            _.each(this._opt.fields, function (item, idx) {
                if (item.type == "prikey") {
                    scope.appendPrikey(item);
                    return;
                }
                if ((pos + item.span) > scope._opt.cols) {
                    content += "</tr><tr>";
                    pos = item.span;
                } else {
                    pos += item.span;
                }
                let sndSpan = (item.span > 1) ? item.span * 2 - 1 : 1;
                content += `<td class="greyTD">${item.title}</td>`;
                content += `<td colspan="${sndSpan}">`;
                content += scope.renderFuncMapper[item.type].call(scope, item);
                content += `</td>`;
            });
            content += "</tr><tbody>";
            this.$table.append(content);
            //绑定日期 的方法
            this.$table.find('[data-type="date"]').autoDate("nyr");
            this.$table.find('[data-type="month"]').autoDate("ny");
            this.$table.find('[data-type="year"]').autoDate("n");
        }
        /**绑定一下取消和保存的事件*/
        public bindClickEvent() {
            let scope = this;
            this.$btnCancle.click(function () {
                //直接是触发用户事件
                scope._opt.canceled && scope._opt.canceled();
            });
            this.$btnSave.click(function () {
                scope.saveData();
                return false;
            });
        }
        public appendPrikey(item: AutoFormFieldsOptions) {
            this.$form.append(` <input name="${item.field}" type="hidden" value="">`);
            this.keysList.push(item.field);
        }
        private getPlaceholder(item: AutoFormFieldsOptions) {
            return item.placeholder ? `placeholder="${item.placeholder}"` : "";
        }
        public renderString(item: AutoFormFieldsOptions) {
            return `<input type="text" data-type="string" name="${item.field}"  ${this.getPlaceholder(item)}/>`;
        }
        public renderNumber(item: AutoFormFieldsOptions) {
            return `<input type="number" data-type="number" name="${item.field}" step='${item.step}'  ${this.getPlaceholder(item)}/>`;
        }
        private renderOptions(list: any[]) {
            let content = "";
            content += '<option value="">请选择</option>'
            _.each(list, function (item) {
                content += `<option value="${item["ID"]}">${item["MC"]}</option>;`
            });
            return content;
        }
        /**输出下拉选择， 有异步事件 */
        public renderSelect(item: AutoFormFieldsOptions) {
            let scope = this;
            let content = `<select data-type="select" name="${item.field}" >`;
            if (_.isString(item.addData)) {
                //插入一个等待
                scope.waitCount++;
                $.ajax(<string>item.addData, { type: 'GET', data: {}, dataType: 'json' })
                    .done(function (data) {
                        //异步写入下拉菜单
                        scope.$form.find(`[name=${item.field}]`).append(scope.renderOptions(<any[]>data));
                        scope.waitCount--;
                    });
            } else if (_.isArray(item.addData)) {
                content += scope.renderOptions(<any[]>item.addData);
            }
            content += '</select>';
            return content;
        }
        /**输出下拉树， 有异步事件 */
        public renderTree(item: AutoFormFieldsOptions) {
            let scope = this;
            //隐藏标签用于提交value
            let content = `<input type="hidden" data-type="tree" name="${item.field}" />`;
            //显示值对应的名称。它没有name属性性，所以不提交
            content += `<input type="text" class='formtreeInput' data-type="tree" data-label="${item.field}"  ${this.getPlaceholder(item)}/>`;
            //插入一个等待
            scope.waitCount++;
            content += (`<div class="formtree ztree"></div>`);
            //请求树数据,同时
            $.ajax(<string>item.addData, { type: 'GET', data: {}, dataType: 'json' })
                .done(function (treedata) {
                    /* _.each(treedata, function(node) {
                             if(node.ISLEAF == "1") {
                                 node.icon = "scripts/pluginjs/zTree3.5.21/css/zTreeStyle/img/diy/10.png";
                             } else {
                                 node.iconOpen = "scripts/pluginjs/zTree3.5.21/css/zTreeStyle/img/diy/1_open.png";
                                 node.iconClose = "scripts/pluginjs/zTree3.5.21/css/zTreeStyle/img/diy/1_close.png";
                             }
                         });
                     */
                    let $input = scope.$form.find(`[name=${item.field}]`)
                        .data("treedata", treedata);
                    let $text = $input.next();
                    let $tree = $text.next();
                    //生成树
                    var setting = {
                        data: {
                            key: { name: "NAME" },
                            simpleData: { enable: true, idKey: "ID", pIdKey: "PID" }
                        },
                        callback: {
                            onDblClick: function (event, treeId, treeNode: TreeNode) {
                                if (treeNode && treeNode.ISLEAF == '1') {
                                    $input.val(treeNode.ID);
                                    $text.val(treeNode.NAME);
                                }
                            }
                        }
                    };
                    //生成树，并打开第一级目录
                    var treeObj = $.fn.zTree.init($tree, setting, treedata);
                    var nodes = treeObj.getNodes();
                    treeObj.expandNode(nodes[0], true, false, true);
                    $input.parent().addClass("formtreeTd");
                    scope.waitCount--;
                });
            return content;
        }
        public renderDate(item: AutoFormFieldsOptions) {
            //日期列要增加_RQ的后缀，在后台处理过程中，会将其去掉。
            return `<input type="text" data-type="date" name="${item.field}_RQ" ${this.getPlaceholder(item)}/>`;
        }
        public renderMonth(item: AutoFormFieldsOptions) {
            return `<input type="text" data-type="month" name="${item.field}" ${this.getPlaceholder(item)}/>`;
        }
        public renderYear(item: AutoFormFieldsOptions) {
            return `<input type="text" data-type="year" name="${item.field}" ${this.getPlaceholder(item)}/>`;
        }
        public renderFile(item: AutoFormFieldsOptions) {
            return "<input type=\"file\" data-type=\"file\" id=\"uploadfile\" name=\"" +
                item.field + "\" " + this.getPlaceholder(item) + "/>";
        };
        public renderTextarea(item: AutoFormFieldsOptions) {
            return "<textarea style='width:100%;height:80px' rows='3' data-type=\"string\" name=\"" +
                item.field + "\" " + this.getPlaceholder(item) + "/>";
        };
        public renderPassword(item: AutoFormFieldsOptions) {
            return "<input type=\"password\" data-type=\"string\" name=\"" + item.field + "\" " + this.getPlaceholder(item) + "/>";
        };
        /** 如果传入了formValues ,那么要将它写到表单中 */
        public writeValues() {
            let scope = this;
            //sql返回的对象一般是一个元素的数组，所以直接取0个元素
            if (!scope._opt.values) return;
            
            let row = scope._opt.values[0];
            if (this.waitCount > 0) {
                setTimeout(function () {
                    scope.writeValues();
                }, 500);
            } else {
                _.each(this._opt.fields, function (item, idx) {
                    //特殊考虑  日期\树\文件 类型
                    let $input = scope.$form.find(`[name=${item.field}${item.type == "date" ? "_RQ" : ""}]`);
                    let value = row[item.field];
                    if (value) {
                        if (item.type == "date") {
                            value = row[item.field].substr(0, 10);
                        } else if (item.type == "tree") {
                            let $text = $input.next();
                            let $tree = $text.next();
                            let treedata: TreeNode[] = $input.data("treedata");
                            let treenode = _.find(treedata, function (node) {
                                return node["ID"] == value;
                            });
                            $input.val(treenode.ID)
                            $text.val(treenode.NAME);
                        } else if (item.type != "file") {
                            $input.val(value);
                        }
                    }
                });
            }
        }
        /**首先走beforeSave ,
         *     返回false,则保留页面，让用户修改，
         *     否则
         *         如果是form提交，页面就切换了。
                   如果ajax提交，提交后执行用户saved方法*/
        private saveData(): boolean {
            let scope = this;
            let updata = this.$form.serializeArray();
            updata.push({ name: "_keys", value: this.keysList.join(",") });
            updata.push({ name: "_table", value: this._opt.tableName });
            //如果beforeSave返回false,则终止上传操作。
            if (_.isFunction(scope._opt.beforeSave) && !scope._opt.beforeSave(updata)) {
                return false;
            }
            if (this._opt.action == "") {
                $.ajax(this._opt.ajaxurl, { type: 'POST', data: updata, dataType: 'json' })
                    .done(function (msg) {
                        //触发用户的事件
                        scope._opt.saved && scope._opt.saved(msg);
                    });
            } else {
                (<HTMLFormElement>this.$form[0]).submit();
            }
            return true;
        }
    }
}